home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume2 / remote < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  27.1 KB

  1. From: Arnold Robbins <gatech!arnold>
  2. Subject: Remote mag tape routines
  3. Keywords: remote magnetic tapes, tar, dd
  4. Newsgroups: mod.sources
  5. Approved: john@genrad.UUCP
  6.  
  7. Mod.sources:  Volume 2, Issue 21
  8. Submitted by: Arnold Robbins <gatech!arnold>
  9. Title: Remote mag tape routines, re-written as a general library (+ tar, dd)
  10.  
  11.  
  12. Although the remote mag tape stuff for tar was just posted recently, this
  13. is worth re-posting since it 1) fixes a few bugs, and 2) provides a much more
  14. general facility for accessing remote tape drives.  E.g., to fix dd for
  15. remote tape drives, all I had to do was add one line and recompile with
  16. the library.
  17.  
  18. Credit is given in the man page for the people who did the work.
  19.  
  20. Enjoy,
  21.  
  22. Arnold Robbins
  23. CSNET:    arnold@gatech    ARPA:    arnold%gatech.csnet@csnet-relay.arpa
  24. UUCP:    { akgua, allegra, hplabs, ihnp4, seismo, ut-sally }!gatech!arnold
  25. --------------------- axe your screen here -----------------------
  26. #!/bin/sh
  27. # This is a shell archive, meaning:
  28. # 1. Remove everything above the #!/bin/sh line.
  29. # 2. Save the resulting text in a file.
  30. # 3. Execute the file with /bin/sh (not csh) to create the files:
  31. #    README
  32. #    dd.1.DIFF
  33. #    dd.c.DIFF
  34. #    rmt.h
  35. #    rmtlib.c
  36. #    rmtops.3
  37. #    tar.1.DIFF
  38. #    tar.c.DIFF
  39. # This archive created: Mon Jul 29 13:04:33 1985
  40. # By:    Arnold Robbins (Pr1mebusters!)
  41. export PATH; PATH=/bin:$PATH
  42. echo shar: extracting "'README'" '(851 characters)'
  43. if test -f 'README'
  44. then
  45.     echo shar: over-writing existing file "'README'"
  46. fi
  47. cat << \SHAR_EOF > 'README'
  48. README  --- remote mag tape library and diffs for tar(1) and dd(1)
  49.  
  50. The files in this directory implement a library of routines which allow
  51. a user using the Unix system calls for i/o to transparently access a tape
  52. drive on a remote machine, via rsh(1) and rmt(8).
  53.  
  54. The files are as follows:
  55.  
  56. README        ---    This file.
  57. dd.1.DIFF    ---    Context diff for dd(1) man page.
  58. dd.c.DIFF    ---    Context diff for dd.c source code.
  59. tar.1.DIFF    ---    Context diff for tar(1) man page.
  60. tar.c.DIFF    ---    Context diff for tar.c source code.
  61. rmt.h        ---    Remote mag tape include file.
  62. rmtlib.c    ---    Remote mag tape library source code.
  63. rmtops.3    ---    Remote mag tape library man page.
  64.  
  65. The diffs are for BRL Unix 3.0 (4.2 BSD), your line numbers may vary.
  66. The tar(1) diffs include a fix to keep tar from damaging the file system;
  67. existing directories are removed only if they are empty.
  68. SHAR_EOF
  69. echo shar: extracting "'dd.1.DIFF'" '(1273 characters)'
  70. if test -f 'dd.1.DIFF'
  71. then
  72.     echo shar: over-writing existing file "'dd.1.DIFF'"
  73. fi
  74. cat << \SHAR_EOF > 'dd.1.DIFF'
  75. *** /usr/man/man1/dd.1    Mon Apr  4 06:12:26 1983
  76. --- dd.1    Wed Jul 24 12:29:58 1985
  77. ***************
  78. *** 23,29
  79.   .ns
  80.   .TP 
  81.   if=
  82. ! input file name; standard input is default
  83.   .br
  84.   .ns
  85.   .TP 
  86.  
  87. --- 23,45 -----
  88.   .ns
  89.   .TP 
  90.   if=
  91. ! input file name; standard input is default.
  92. ! If the input file name has the form
  93. ! .IR system [. user ]:/dev/???,
  94. ! then
  95. ! .I dd
  96. ! will attempt to use the tape drive /dev/??? on the remote system
  97. ! .IR system ,
  98. ! via
  99. ! .IR rsh (1),
  100. ! and
  101. ! .IR rmt (8).
  102. ! The optional
  103. ! .I user
  104. ! specifies the login name to use on the remote system.
  105. ! If it is not given, the current user's login name will be used.
  106. ! In all cases, the user must have the appropriate
  107. ! access permissions on the remote machine in order for this to work.
  108.   .br
  109.   .ns
  110.   .TP 
  111. ***************
  112. *** 28,34
  113.   .ns
  114.   .TP 
  115.   of=
  116. ! output file name; standard output is default
  117.   .br
  118.   .ns
  119.   .TP 
  120.  
  121. --- 44,51 -----
  122.   .ns
  123.   .TP 
  124.   of=
  125. ! output file name; standard output is default,
  126. ! remote file names may be used here as well.
  127.   .br
  128.   .ns
  129.   .TP 
  130. ***************
  131. *** 203,205
  132.   raw disks with bad sectors to insure 
  133.   .I dd
  134.   stays synchronized.
  135.  
  136. --- 220,224 -----
  137.   raw disks with bad sectors to insure 
  138.   .I dd
  139.   stays synchronized.
  140. + .br
  141. + Using a remote system's tape drive can be slow.
  142. SHAR_EOF
  143. echo shar: extracting "'dd.c.DIFF'" '(360 characters)'
  144. if test -f 'dd.c.DIFF'
  145. then
  146.     echo shar: over-writing existing file "'dd.c.DIFF'"
  147. fi
  148. cat << \SHAR_EOF > 'dd.c.DIFF'
  149. *** /usr/src/bin/dd.c    Fri Apr 29 04:20:35 1983
  150. --- dd.c    Tue Jul 23 14:13:53 1985
  151. ***************
  152. *** 2,7
  153.   #include <stdio.h>
  154.   #include <signal.h>
  155.   
  156.   #define    BIG    2147483647
  157.   #define    LCASE    01
  158.   #define    UCASE    02
  159.  
  160. --- 2,9 -----
  161.   #include <stdio.h>
  162.   #include <signal.h>
  163.   
  164. + #include <rmt.h>
  165.   #define    BIG    2147483647
  166.   #define    LCASE    01
  167.   #define    UCASE    02
  168. SHAR_EOF
  169. echo shar: extracting "'rmt.h'" '(904 characters)'
  170. if test -f 'rmt.h'
  171. then
  172.     echo shar: over-writing existing file "'rmt.h'"
  173. fi
  174. cat << \SHAR_EOF > 'rmt.h'
  175. /*
  176.  *    rmt.h
  177.  *
  178.  *    Added routines to replace open(), close(), lseek(), ioctl(), etc.
  179.  *    The preprocessor can be used to remap these the rmtopen(), etc
  180.  *    thus minimizing source changes.
  181.  *
  182.  *    This file must be included before <sys/stat.h>, since it redefines
  183.  *    stat to be rmtstat, so that struct stat xyzzy; declarations work
  184.  *    properly.
  185.  *
  186.  *    -- Fred Fish (w/some changes by Arnold Robbins)
  187.  */
  188.  
  189.  
  190. #ifndef access        /* avoid multiple redefinition */
  191. #ifndef lint        /* in this case what lint doesn't know won't hurt it */
  192. #define access rmtaccess
  193. #define close rmtclose
  194. #define creat rmtcreat
  195. #define dup rmtdup
  196. #define fcntl rmtfcntl
  197. #define fstat rmtfstat
  198. #define ioctl rmtioctl
  199. #define isatty rmtisatty
  200. #define lseek rmtlseek
  201. #define lstat rmtlstat
  202. #define open rmtopen
  203. #define read rmtread
  204. #define stat rmtstat
  205. #define write rmtwrite
  206.  
  207. extern long rmtlseek ();    /* all the rest are int's */
  208. #endif
  209. #endif
  210. SHAR_EOF
  211. echo shar: extracting "'rmtlib.c'" '(13608 characters)'
  212. if test -f 'rmtlib.c'
  213. then
  214.     echo shar: over-writing existing file "'rmtlib.c'"
  215. fi
  216. cat << \SHAR_EOF > 'rmtlib.c'
  217. /*
  218.  *    rmt --- remote tape emulator subroutines
  219.  *
  220.  *    Originally written by Jeff Lee, modified some by Arnold Robbins
  221.  *
  222.  *    WARNING:  The man page rmt(8) for /etc/rmt documents the remote mag
  223.  *    tape protocol which rdump and rrestore use.  Unfortunately, the man
  224.  *    page is *WRONG*.  The author of the routines I'm including originally
  225.  *    wrote his code just based on the man page, and it didn't work, so he
  226.  *    went to the rdump source to figure out why.  The only thing he had to
  227.  *    change was to check for the 'F' return code in addition to the 'E',
  228.  *    and to separate the various arguments with \n instead of a space.  I
  229.  *    personally don't think that this is much of a problem, but I wanted to
  230.  *    point it out.
  231.  *    -- Arnold Robbins
  232.  *
  233.  *    Redone as a library that can replace open, read, write, etc, by
  234.  *    Fred Fish, with some additional work by Arnold Robbins.
  235.  */
  236.  
  237. /*
  238.  *    MAXUNIT --- Maximum number of remote tape file units
  239.  *
  240.  *    READ --- Return the number of the read side file descriptor
  241.  *    WRITE --- Return the number of the write side file descriptor
  242.  */
  243.  
  244. #define RMTIOCTL    1
  245.  
  246. #include <stdio.h>
  247. #include <signal.h>
  248. #include <sys/types.h>
  249.  
  250. #ifdef RMTIOCTL
  251. #include <sys/ioctl.h>
  252. #include <sys/mtio.h>
  253. #endif
  254.  
  255. #include <errno.h>
  256. #include <setjmp.h>
  257. #include <sys/stat.h>
  258.  
  259. #define BUFMAGIC    64    /* a magic number for buffer sizes */
  260. #define MAXUNIT    4
  261.  
  262. #define READ(fd)    (Ctp[fd][0])
  263. #define WRITE(fd)    (Ptc[fd][1])
  264.  
  265. static int Ctp[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  266. static int Ptc[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  267.  
  268. static jmp_buf Jmpbuf;
  269. extern int errno;
  270.  
  271. /*
  272.  *    abort --- close off a remote tape connection
  273.  */
  274.  
  275. static void abort(fildes)
  276. int fildes;
  277. {
  278.     close(READ(fildes));
  279.     close(WRITE(fildes));
  280.     READ(fildes) = -1;
  281.     WRITE(fildes) = -1;
  282. }
  283.  
  284.  
  285.  
  286. /*
  287.  *    command --- attempt to perform a remote tape command
  288.  */
  289.  
  290. static int command(fildes, buf)
  291. int fildes;
  292. char *buf;
  293. {
  294.     register int blen;
  295.     int (*pstat)();
  296.  
  297. /*
  298.  *    save current pipe status and try to make the request
  299.  */
  300.  
  301.     blen = strlen(buf);
  302.     pstat = signal(SIGPIPE, SIG_IGN);
  303.     if (write(WRITE(fildes), buf, blen) == blen)
  304.     {
  305.         signal(SIGPIPE, pstat);
  306.         return(0);
  307.     }
  308.  
  309. /*
  310.  *    something went wrong. close down and go home
  311.  */
  312.  
  313.     signal(SIGPIPE, pstat);
  314.     abort(fildes);
  315.  
  316.     errno = EIO;
  317.     return(-1);
  318. }
  319.  
  320.  
  321.  
  322. /*
  323.  *    status --- retrieve the status from the pipe
  324.  */
  325.  
  326. static int status(fildes)
  327. int fildes;
  328. {
  329.     int i;
  330.     char c, *cp;
  331.     char buffer[BUFMAGIC];
  332.  
  333. /*
  334.  *    read the reply command line
  335.  */
  336.  
  337.     for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++)
  338.     {
  339.         if (read(READ(fildes), cp, 1) != 1)
  340.         {
  341.             abort(fildes);
  342.             errno = EIO;
  343.             return(-1);
  344.         }
  345.         if (*cp == '\n')
  346.         {
  347.             *cp = 0;
  348.             break;
  349.         }
  350.     }
  351.  
  352.     if (i == BUFMAGIC)
  353.     {
  354.         abort(fildes);
  355.         errno = EIO;
  356.         return(-1);
  357.     }
  358.  
  359. /*
  360.  *    check the return status
  361.  */
  362.  
  363.     for (cp = buffer; *cp; cp++)
  364.         if (*cp != ' ')
  365.             break;
  366.  
  367.     if (*cp == 'E' || *cp == 'F')
  368.     {
  369.         errno = atoi(cp + 1);
  370.         while (read(READ(fildes), &c, 1) == 1)
  371.             if (c == '\n')
  372.                 break;
  373.  
  374.         if (*cp == 'F')
  375.             abort(fildes);
  376.  
  377.         return(-1);
  378.     }
  379.  
  380. /*
  381.  *    check for mis-synced pipes
  382.  */
  383.  
  384.     if (*cp != 'A')
  385.     {
  386.         abort(fildes);
  387.         errno = EIO;
  388.         return(-1);
  389.     }
  390.  
  391.     return(atoi(cp + 1));
  392. }
  393.  
  394.  
  395.  
  396. /*
  397.  *    _rmt_open --- open a magtape device on system specified, as given user
  398.  *
  399.  *    file name has the form system[.user]:/dev/????
  400.  */
  401.  
  402. #define MAXHOSTLEN    257    /* BSD allows very long host names... */
  403.  
  404. static int _rmt_open (path, oflag, mode)
  405. char *path;
  406. int oflag;
  407. int mode;
  408. {
  409.     int i, rc;
  410.     char buffer[BUFMAGIC];
  411.     char system[MAXHOSTLEN];
  412.     char device[BUFMAGIC];
  413.     char login[BUFMAGIC];
  414.     char *sys, *dev, *user;
  415.  
  416.     sys = system;
  417.     dev = device;
  418.     user = login;
  419.  
  420. /*
  421.  *    first, find an open pair of file descriptors
  422.  */
  423.  
  424.     for (i = 0; i < MAXUNIT; i++)
  425.         if (READ(i) == -1 && WRITE(i) == -1)
  426.             break;
  427.  
  428.     if (i == MAXUNIT)
  429.     {
  430.         errno = EMFILE;
  431.         return(-1);
  432.     }
  433.  
  434. /*
  435.  *    pull apart system and device, and optional user
  436.  *    don't munge original string
  437.  */
  438.     while (*path != '.' && *path != ':') {
  439.         *sys++ = *path++;
  440.     }
  441.     *sys = '\0';
  442.     path++;
  443.  
  444.     if (*(path - 1) == '.')
  445.     {
  446.         while (*path != ':') {
  447.             *user++ = *path++;
  448.         }
  449.         *user = '\0';
  450.         path++;
  451.     }
  452.     else
  453.         *user = '\0';
  454.  
  455.     while (*path) {
  456.         *dev++ = *path++;
  457.     }
  458.     *dev = '\0';
  459.  
  460. /*
  461.  *    setup the pipes for the 'rsh' command and fork
  462.  */
  463.  
  464.     if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
  465.         return(-1);
  466.  
  467.     if ((rc = fork()) == -1)
  468.         return(-1);
  469.  
  470.     if (rc == 0)
  471.     {
  472.         close(0);
  473.         dup(Ptc[i][0]);
  474.         close(Ptc[i][0]); close(Ptc[i][1]);
  475.         close(1);
  476.         dup(Ctp[i][1]);
  477.         close(Ctp[i][0]); close(Ctp[i][1]);
  478.         (void) setuid (getuid ());
  479.         (void) setgid (getgid ());
  480.         if (*user)
  481.         {
  482.             execl("/usr/ucb/rsh", "rsh", system, "-l", login,
  483.                 "/etc/rmt", (char *) 0);
  484.             execl("/usr/bin/remsh", "remsh", system, "-l", login,
  485.                 "/etc/rmt", (char *) 0);
  486.         }
  487.         else
  488.         {
  489.             execl("/usr/ucb/rsh", "rsh", system,
  490.                 "/etc/rmt", (char *) 0);
  491.             execl("/usr/bin/remsh", "remsh", system,
  492.                 "/etc/rmt", (char *) 0);
  493.         }
  494.  
  495. /*
  496.  *    bad problems if we get here
  497.  */
  498.  
  499.         perror("exec");
  500.         exit(1);
  501.     }
  502.  
  503.     close(Ptc[i][0]); close(Ctp[i][1]);
  504.  
  505. /*
  506.  *    now attempt to open the tape device
  507.  */
  508.  
  509.     sprintf(buffer, "O%s\n%d\n", device, oflag);
  510.     if (command(i, buffer) == -1 || status(i) == -1)
  511.         return(-1);
  512.  
  513.     return(i);
  514. }
  515.  
  516.  
  517.  
  518. /*
  519.  *    _rmt_close --- close a remote magtape unit and shut down
  520.  */
  521.  
  522. static int _rmt_close(fildes)
  523. int fildes;
  524. {
  525.     int rc;
  526.  
  527.     if (command(fildes, "C\n") != -1)
  528.     {
  529.         rc = status(fildes);
  530.  
  531.         abort(fildes);
  532.         return(rc);
  533.     }
  534.  
  535.     return(-1);
  536. }
  537.  
  538.  
  539.  
  540. /*
  541.  *    _rmt_read --- read a buffer from a remote tape
  542.  */
  543.  
  544. static int _rmt_read(fildes, buf, nbyte)
  545. int fildes;
  546. char *buf;
  547. unsigned int nbyte;
  548. {
  549.     int rc, i;
  550.     char buffer[BUFMAGIC];
  551.  
  552.     sprintf(buffer, "R%d\n", nbyte);
  553.     if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
  554.         return(-1);
  555.  
  556.     for (i = 0; i < rc; i += nbyte, buf += nbyte)
  557.     {
  558.         nbyte = read(READ(fildes), buf, rc);
  559.         if (nbyte <= 0)
  560.         {
  561.             abort(fildes);
  562.             errno = EIO;
  563.             return(-1);
  564.         }
  565.     }
  566.  
  567.     return(rc);
  568. }
  569.  
  570.  
  571.  
  572. /*
  573.  *    _rmt_write --- write a buffer to the remote tape
  574.  */
  575.  
  576. static int _rmt_write(fildes, buf, nbyte)
  577. int fildes;
  578. char *buf;
  579. unsigned int nbyte;
  580. {
  581.     int rc;
  582.     char buffer[BUFMAGIC];
  583.     int (*pstat)();
  584.  
  585.     sprintf(buffer, "W%d\n", nbyte);
  586.     if (command(fildes, buffer) == -1)
  587.         return(-1);
  588.  
  589.     pstat = signal(SIGPIPE, SIG_IGN);
  590.     if (write(WRITE(fildes), buf, nbyte) == nbyte)
  591.     {
  592.         signal (SIGPIPE, pstat);
  593.         return(status(fildes));
  594.     }
  595.  
  596.     signal (SIGPIPE, pstat);
  597.     abort(fildes);
  598.     errno = EIO;
  599.     return(-1);
  600. }
  601.  
  602.  
  603.  
  604. /*
  605.  *    _rmt_lseek --- perform an imitation lseek operation remotely
  606.  */
  607.  
  608. static long _rmt_lseek(fildes, offset, whence)
  609. int fildes;
  610. long offset;
  611. int whence;
  612. {
  613.     char buffer[BUFMAGIC];
  614.  
  615.     sprintf(buffer, "L%d\n%d\n", offset, whence);
  616.     if (command(fildes, buffer) == -1)
  617.         return(-1);
  618.  
  619.     return(status(fildes));
  620. }
  621.  
  622.  
  623. #ifdef RMTIOCTL
  624. /*
  625.  *    _rmt_ioctl --- perform raw tape operations remotely
  626.  */
  627.  
  628. static _rmt_ioctl(fildes, op, arg)
  629. int fildes, op;
  630. char *arg;
  631. {
  632.     char c;
  633.     int rc, cnt;
  634.     char buffer[BUFMAGIC];
  635.  
  636. /*
  637.  *    MTIOCOP is the easy one. nothing is transfered in binary
  638.  */
  639.  
  640.     if (op == MTIOCTOP)
  641.     {
  642.         sprintf(buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
  643.             ((struct mtop *) arg)->mt_count);
  644.         if (command(fildes, buffer) == -1)
  645.             return(-1);
  646.         return(status(fildes));
  647.     }
  648.  
  649. /*
  650.  *    we can only handle 2 ops, if not the other one, punt
  651.  */
  652.  
  653.     if (op != MTIOCGET)
  654.     {
  655.         errno = EINVAL;
  656.         return(-1);
  657.     }
  658.  
  659. /*
  660.  *    grab the status and read it directly into the structure
  661.  *    this assumes that the status buffer is (hopefully) not
  662.  *    padded and that 2 shorts fit in a long without any word
  663.  *    alignment problems, ie - the whole struct is contiguous
  664.  *    NOTE - this is probably NOT a good assumption.
  665.  */
  666.  
  667.     if (command(fildes, "S\n") == -1 || (rc = status(fildes)) == -1)
  668.         return(-1);
  669.  
  670.     for (; rc > 0; rc -= cnt, arg += cnt)
  671.     {
  672.         cnt = read(READ(fildes), arg, rc);
  673.         if (cnt <= 0)
  674.         {
  675.             abort(fildes);
  676.             errno = EIO;
  677.             return(-1);
  678.         }
  679.     }
  680.  
  681. /*
  682.  *    now we check for byte position. mt_type is a small integer field
  683.  *    (normally) so we will check its magnitude. if it is larger than
  684.  *    256, we will assume that the bytes are swapped and go through
  685.  *    and reverse all the bytes
  686.  */
  687.  
  688.     if (((struct mtget *) arg)->mt_type < 256)
  689.         return(0);
  690.  
  691.     for (cnt = 0; cnt < rc; cnt += 2)
  692.     {
  693.         c = arg[cnt];
  694.         arg[cnt] = arg[cnt+1];
  695.         arg[cnt+1] = c;
  696.     }
  697.  
  698.     return(0);
  699.   }
  700. #endif /* RMTIOCTL */
  701.  
  702. /*
  703.  *    Added routines to replace open(), close(), lseek(), ioctl(), etc.
  704.  *    The preprocessor can be used to remap these the rmtopen(), etc
  705.  *    thus minimizing source changes:
  706.  *
  707.  *        #ifdef REMOTETAPE
  708.  *        #  define access rmtaccess
  709.  *        #  define close rmtclose
  710.  *        #  define creat rmtcreat
  711.  *        #  define dup rmtdup
  712.  *        #  define fcntl rmtfcntl
  713.  *        #  define fstat rmtfstat
  714.  *        #  define ioctl rmtioctl
  715.  *        #  define isatty rmtisatty
  716.  *        #  define lseek rmtlseek
  717.  *        #  define lstat rmtlstat
  718.  *        #  define open rmtopen
  719.  *        #  define read rmtread
  720.  *        #  define stat rmtstat
  721.  *        #  define write rmtwrite
  722.  *        #  define access rmtaccess
  723.  *        #  define close rmtclose
  724.  *        #  define creat rmtcreat
  725.  *        #  define dup rmtdup
  726.  *        #  define fcntl rmtfcntl
  727.  *        #  define fstat rmtfstat
  728.  *        #  define ioctl rmtioctl
  729.  *        #  define lseek rmtlseek
  730.  *        #  define open rmtopen
  731.  *        #  define read rmtread
  732.  *        #  define stat rmtstat
  733.  *        #  define write rmtwrite
  734.  *        #endif
  735.  *
  736.  *    -- Fred Fish
  737.  *
  738.  *    ADR --- I set up a <rmt.h> include file for this
  739.  *
  740.  */
  741.  
  742. /*
  743.  *    Note that local vs remote file descriptors are distinquished
  744.  *    by adding a bias to the remote descriptors.  This is a quick
  745.  *    and dirty trick that may not be portable to some systems.
  746.  */
  747.  
  748. #define REM_BIAS 128
  749.  
  750.  
  751. /*
  752.  *    Test pathname to see if it is local or remote.  A remote device
  753.  *    is any string that contains ":/dev/".  Returns 1 if remote,
  754.  *    0 otherwise.
  755.  */
  756.  
  757. static int remdev (path)
  758. register char *path;
  759. {
  760. #define strchr    index
  761.     extern char *strchr ();
  762.  
  763.     if ((path = strchr (path, ':')) != NULL)
  764.     {
  765.         if (strncmp (path + 1, "/dev/", 5) == 0)
  766.         {
  767.             return (1);
  768.         }
  769.     }
  770.     return (0);
  771. }
  772.  
  773.  
  774. /*
  775.  *    Open a local or remote file.  Looks just like open(2) to
  776.  *    caller.
  777.  */
  778.  
  779. int rmtopen (path, oflag, mode)
  780. char *path;
  781. int oflag;
  782. int mode;
  783. {
  784.     if (remdev (path))
  785.     {
  786.         return (_rmt_open (path, oflag, mode) + REM_BIAS);
  787.     }
  788.     else
  789.     {
  790.         return (open (path, oflag, mode));
  791.     }
  792. }
  793.  
  794. /*
  795.  *    Test pathname for specified access.  Looks just like access(2)
  796.  *    to caller.
  797.  */
  798.  
  799. int rmtaccess (path, amode)
  800. char *path;
  801. int amode;
  802. {
  803.     if (remdev (path))
  804.     {
  805.         return (0);        /* Let /etc/rmt find out */
  806.     }
  807.     else
  808.     {
  809.         return (access (path, amode));
  810.     }
  811. }
  812.  
  813.  
  814. /*
  815.  *    Read from stream.  Looks just like read(2) to caller.
  816.  */
  817.   
  818. int rmtread (fildes, buf, nbyte)
  819. int fildes;
  820. char *buf;
  821. unsigned int nbyte;
  822. {
  823.     if (isrmt (fildes))
  824.     {
  825.         return (_rmt_read (fildes - REM_BIAS, buf, nbyte));
  826.     }
  827.     else
  828.     {
  829.         return (read (fildes, buf, nbyte));
  830.     }
  831. }
  832.  
  833.  
  834. /*
  835.  *    Write to stream.  Looks just like write(2) to caller.
  836.  */
  837.  
  838. int rmtwrite (fildes, buf, nbyte)
  839. int fildes;
  840. char *buf;
  841. unsigned int nbyte;
  842. {
  843.     if (isrmt (fildes))
  844.     {
  845.         return (_rmt_write (fildes - REM_BIAS, buf, nbyte));
  846.     }
  847.     else
  848.     {
  849.         return (write (fildes, buf, nbyte));
  850.     }
  851. }
  852.  
  853. /*
  854.  *    Perform lseek on file.  Looks just like lseek(2) to caller.
  855.  */
  856.  
  857. long rmtlseek (fildes, offset, whence)
  858. int fildes;
  859. long offset;
  860. int whence;
  861. {
  862.     if (isrmt (fildes))
  863.     {
  864.         return (_rmt_lseek (fildes - REM_BIAS, offset, whence));
  865.     }
  866.     else
  867.     {
  868.         return (lseek (fildes, offset, whence));
  869.     }
  870. }
  871.  
  872.  
  873. /*
  874.  *    Close a file.  Looks just like close(2) to caller.
  875.  */
  876.  
  877. int rmtclose (fildes)
  878. int fildes;
  879. {
  880.     if (isrmt (fildes))
  881.     {
  882.         return (_rmt_close (fildes - REM_BIAS));
  883.     }
  884.     else
  885.     {
  886.         return (close (fildes));
  887.     }
  888. }
  889.  
  890. /*
  891.  *    Do ioctl on file.  Looks just like ioctl(2) to caller.
  892.  */
  893.  
  894. int rmtioctl (fildes, request, arg)
  895. int fildes, request, arg;
  896. {
  897.     if (isrmt (fildes))
  898.     {
  899.         errno = EOPNOTSUPP;
  900.         return (-1);        /* For now  (fnf) */
  901.     }
  902.     else
  903.     {
  904.         return (ioctl (fildes, request, arg));
  905.     }
  906. }
  907.  
  908.  
  909. /*
  910.  *    Duplicate an open file descriptor.  Looks just like dup(2)
  911.  *    to caller.
  912.  */
  913.  
  914. int rmtdup (fildes)
  915. int fildes;
  916. {
  917.     if (isrmt (fildes))
  918.     {
  919.         errno = EOPNOTSUPP;
  920.         return (-1);        /* For now (fnf) */
  921.     }
  922.     else
  923.     {
  924.         return (dup (fildes));
  925.     }
  926. }
  927.  
  928. /*
  929.  *    Get file status.  Looks just like fstat(2) to caller.
  930.  */
  931.  
  932. int rmtfstat (fildes, buf)
  933. int fildes;
  934. struct stat *buf;
  935. {
  936.     if (isrmt (fildes))
  937.     {
  938.         errno = EOPNOTSUPP;
  939.         return (-1);        /* For now (fnf) */
  940.     }
  941.     else
  942.     {
  943.         return (fstat (fildes, buf));
  944.     }
  945. }
  946.  
  947.  
  948. /*
  949.  *    Get file status.  Looks just like stat(2) to caller.
  950.  */
  951.  
  952. int rmtstat (path, buf)
  953. char *path;
  954. struct stat *buf;
  955. {
  956.     if (remdev (path))
  957.     {
  958.         errno = EOPNOTSUPP;
  959.         return (-1);        /* For now (fnf) */
  960.     }
  961.     else
  962.     {
  963.         return (stat (path, buf));
  964.     }
  965. }
  966.  
  967.  
  968.  
  969. /*
  970.  *    Create a file from scratch.  Looks just like creat(2) to the caller.
  971.  */
  972.  
  973. #include <sys/file.h>        /* BSD DEPENDANT!!! */
  974. /* #include <fcntl.h>        /* use this one for S5 with remote stuff */
  975.  
  976. int rmtcreat (path, mode)
  977. char *path;
  978. int mode;
  979. {
  980.     if (remdev (path))
  981.     {
  982.         return (rmtopen (path, 1 | O_CREAT, mode));
  983.     }
  984.     else
  985.     {
  986.         return (creat (path, mode));
  987.     }
  988. }
  989.  
  990. /*
  991.  *    Isrmt. Let a programmer know he has a remote device.
  992.  */
  993.  
  994. int isrmt (fd)
  995. int fd;
  996. {
  997.     return (fd >= REM_BIAS);
  998. }
  999.  
  1000. /*
  1001.  *    Rmtfcntl. Do a remote fcntl operation.
  1002.  */
  1003.  
  1004. int rmtfcntl (fd, cmd, arg)
  1005. int fd, cmd, arg;
  1006. {
  1007.     if (isrmt (fd))
  1008.     {
  1009.         errno = EOPNOTSUPP;
  1010.         return (-1);
  1011.     }
  1012.     else
  1013.     {
  1014.         return (fcntl (fd, cmd, arg));
  1015.     }
  1016. }
  1017.  
  1018. /*
  1019.  *    Rmtisatty.  Do the isatty function.
  1020.  */
  1021.  
  1022. int rmtisatty (fd)
  1023. int fd;
  1024. {
  1025.     if (isrmt (fd))
  1026.         return (0);
  1027.     else
  1028.         return (isatty (fd));
  1029. }
  1030.  
  1031.  
  1032. /*
  1033.  *    Get file status, even if symlink.  Looks just like lstat(2) to caller.
  1034.  */
  1035.  
  1036. int rmtlstat (path, buf)
  1037. char *path;
  1038. struct stat *buf;
  1039. {
  1040.     if (remdev (path))
  1041.     {
  1042.         errno = EOPNOTSUPP;
  1043.         return (-1);        /* For now (fnf) */
  1044.     }
  1045.     else
  1046.     {
  1047.         return (lstat (path, buf));
  1048.     }
  1049. }
  1050. SHAR_EOF
  1051. echo shar: extracting "'rmtops.3'" '(4071 characters)'
  1052. if test -f 'rmtops.3'
  1053. then
  1054.     echo shar: over-writing existing file "'rmtops.3'"
  1055. fi
  1056. cat << \SHAR_EOF > 'rmtops.3'
  1057. .TH RMTOPS 3 local
  1058. .SH NAME
  1059. rmtops \- access tape drives on remote machines
  1060. .SH SYNOPSIS
  1061. .nf
  1062. #include <rmt.h>
  1063. #include <sys/stat.h>    /* MUST come after <rmt.h> */
  1064.  
  1065. int isrmt (fd)
  1066. int fd;
  1067.  
  1068. int rmtaccess (file, mode)
  1069. char *file;
  1070. int mode;
  1071.  
  1072. int rmtclose (fd)
  1073. int fd;
  1074.  
  1075. int rmtcreat (file, mode)
  1076. char *file;
  1077. int mode;
  1078.  
  1079. int rmtdup (fd)
  1080. int fd;
  1081.  
  1082. int rmtfcntl (fd, cmd, arg)
  1083. int fd, cmd, arg;
  1084.  
  1085. int rmtfstat (fd, buf)
  1086. int fd;
  1087. struct stat *buf;
  1088.  
  1089. int rmtioctl (fd, request, argp)
  1090. int fd, request;
  1091. char *argp;
  1092.  
  1093. int rmtisatty (fd)
  1094. int fd;
  1095.  
  1096. long rmtlseek (fd, offset, whence)
  1097. int fd, whence;
  1098. long offset;
  1099.  
  1100. int rmtlstat (file, buf)
  1101. char *file;
  1102. struct stat *buf;
  1103.  
  1104. int rmtopen (file, flags [, mode])
  1105. char *file;
  1106. int flags, mode;
  1107.  
  1108. int rmtread (fd, buf, nbytes)
  1109. int fd, nbytes;
  1110. char *buf;
  1111.  
  1112. int rmtstat (file, buf)
  1113. char *file;
  1114. struct stat *buf;
  1115.  
  1116. int rmtwrite (fd, buf, nbytes)
  1117. int fd, nbytes;
  1118. char *buf;
  1119. .fi
  1120. .SH DESCRIPTION
  1121. .I Rmtops
  1122. provides a simple means of transparently accessing tape drives
  1123. on remote machines over the ethernet, via
  1124. .IR rsh (1)
  1125. and
  1126. .IR rmt (8).
  1127. These routines are used like their corresponding
  1128. system calls, but allow the user to open up a tape drive on a remote
  1129. system on which he or she has an account and the appropriate remote
  1130. permissions.
  1131. .PP
  1132. A remote tape drive file name has the form
  1133. .sp
  1134. .RS
  1135. .IR system [. user ]:/dev/???
  1136. .RE
  1137. .sp
  1138. where
  1139. .I system
  1140. is the remote system,
  1141. .I /dev/???
  1142. is the particular drive on the remote system (raw, blocked, rewinding,
  1143. non-rewinding, etc.), and the optional
  1144. .I user
  1145. is the login name to be used on the remote system, if different from
  1146. the current user's login name.
  1147. This corresponds to the remote syntax used by
  1148. .IR rcp (1).
  1149. .PP
  1150. For transparency, the user should include the file
  1151. .IR <rmt.h> ,
  1152. which has the following defines in it:
  1153. .PP
  1154. .nf
  1155. #define access rmtaccess
  1156. #define close rmtclose
  1157. #define creat rmtcreat
  1158. #define dup rmtdup
  1159. #define fcntl rmtfcntl
  1160. #define fstat rmtfstat
  1161. #define ioctl rmtioctl
  1162. #define isatty rmtisatty
  1163. #define lseek rmtlseek
  1164. #define lstat rmtlstat
  1165. #define open rmtopen
  1166. #define read rmtread
  1167. #define stat rmtstat
  1168. #define write rmtwrite
  1169. .fi
  1170. .PP
  1171. This allows the programmer to use
  1172. .IR open ,
  1173. .IR close ,
  1174. .IR read ,
  1175. .IR write ,
  1176. etc. in their normal fashion, with the
  1177. .I rmtops
  1178. routines taking care of differentiating between local and remote files.
  1179. This file should be included
  1180. .I before
  1181. including the file
  1182. .IR <sys/stat.h> ,
  1183. since it redefines the identifier ``stat,'' which is used to declare
  1184. objects of type struct stat.
  1185. .PP
  1186. The routines differentiate between local and remote file descriptors by
  1187. adding a bias (currently 128) to the file descriptor of the pipe.
  1188. The programmer, if he must know if a file is remote, should use the
  1189. .I isrmt
  1190. function.
  1191. .SH FILES
  1192. .TP
  1193. .B /usr/lib/librmt.a
  1194. Contains the remote tape library.  To include the library with a program,
  1195. add the flag
  1196. .I -lrmt
  1197. to the
  1198. .IR cc (1)
  1199. command line.
  1200. .SH SEE ALSO
  1201. .IR rcp (1),
  1202. .IR rsh (1),
  1203. .IR rmt (8),
  1204. and the appropriate system calls in section 2.
  1205. .SH DIAGNOSTICS
  1206. Several of these routines will return -1 and set
  1207. .I errno
  1208. to EOPNOTSUPP, if they are given a remote file name or a file descriptor
  1209. on an open remote file (e.g.,
  1210. .IR rmtdup ).
  1211. .SH BUGS
  1212. See diagnostics above.  It is to be hoped that true remote file systems
  1213. will eventually appear, and eliminate the need for these routines.
  1214. .PP
  1215. There is no way to use remote tape drives with the
  1216. .IR stdio (3)
  1217. package, short of recompiling it entirely to use these routines.
  1218. .PP
  1219. The
  1220. .IR rmt (8)
  1221. protocol is not very capable.  In particular, it relies on
  1222. TCP/IP sockets for error free transmission, and does no data validation
  1223. of its own.
  1224. .PP
  1225. The
  1226. .I rmt
  1227. program allows no more than 10K bytes to be transferred at one time.
  1228. Anymore is truncated.
  1229. .SH AUTHORS
  1230. Jeff Lee (gatech!jeff) wrote the original routines for accessing
  1231. tape drives via
  1232. .IR rmt (8).
  1233. .PP
  1234. Fred Fish (unisoft!fnf) redid them into a general purpose library.
  1235. .PP
  1236. Arnold Robbins (gatech!arnold) added the ability to specify a user
  1237. name on the remote system, the
  1238. .I <rmt.h>
  1239. include file, this man page,
  1240. and cleaned up the library a little.
  1241. SHAR_EOF
  1242. echo shar: extracting "'tar.1.DIFF'" '(1910 characters)'
  1243. if test -f 'tar.1.DIFF'
  1244. then
  1245.     echo shar: over-writing existing file "'tar.1.DIFF'"
  1246. fi
  1247. cat << \SHAR_EOF > 'tar.1.DIFF'
  1248. *** /usr/man/man1/oldtar.1    Mon Jun 27 00:35:14 1983
  1249. --- tar.1    Wed Jul 24 12:28:29 1985
  1250. ***************
  1251. *** 78,84
  1252.   .I tar
  1253.   does its work silently.  The
  1254.   .B v
  1255. ! (verbose) option make
  1256.   .I tar
  1257.   type the name of each file it treats preceded by the function
  1258.   letter.  With the
  1259.  
  1260. --- 78,84 -----
  1261.   .I tar
  1262.   does its work silently.  The
  1263.   .B v
  1264. ! (verbose) option makes
  1265.   .I tar
  1266.   type the name of each file it treats preceded by the function
  1267.   letter.  With the
  1268. ***************
  1269. *** 95,101
  1270.   .B f
  1271.   .I Tar
  1272.   uses the next argument as the name of the archive instead of
  1273. ! /dev/rmt?. If the name of the file is `\-', tar writes to standard output or
  1274.   reads from standard input, whichever is appropriate. Thus,
  1275.   .I tar
  1276.   can be used as the head or tail of a filter chain.
  1277.  
  1278. --- 95,120 -----
  1279.   .B f
  1280.   .I Tar
  1281.   uses the next argument as the name of the archive instead of
  1282. ! /dev/rmt?.
  1283. ! .sp
  1284. ! If the file name has the form
  1285. ! .IR system [. user ]:/dev/???
  1286. ! .I tar
  1287. ! will use the tape drive /dev/??? on the remote system
  1288. ! .IR system ,
  1289. ! via
  1290. ! .IR rsh (1),
  1291. ! and
  1292. ! .IR rmt (8).
  1293. ! The optional
  1294. ! .I user
  1295. ! portion of the pathname specifies the login name to use on the
  1296. ! remote system.
  1297. ! If it is not supplied, the current user's login name will be used.
  1298. ! In all the cases, the user must have the appropriate
  1299. ! permissions on the remote machine, in order to use this facility.
  1300. ! .sp
  1301. ! If the name of the file is `\-', tar writes to standard output or
  1302.   reads from standard input, whichever is appropriate. Thus,
  1303.   .I tar
  1304.   can be used as the head or tail of a filter chain.
  1305. ***************
  1306. *** 179,181
  1307.   The current limit on file name length is 100 characters.
  1308.   .br
  1309.   There is no way to selectively follow symbolic links.
  1310.  
  1311. --- 198,202 -----
  1312.   The current limit on file name length is 100 characters.
  1313.   .br
  1314.   There is no way to selectively follow symbolic links.
  1315. + .br
  1316. + Using a remote system's tape drive can be slow.
  1317. SHAR_EOF
  1318. echo shar: extracting "'tar.c.DIFF'" '(2026 characters)'
  1319. if test -f 'tar.c.DIFF'
  1320. then
  1321.     echo shar: over-writing existing file "'tar.c.DIFF'"
  1322. fi
  1323. cat << \SHAR_EOF > 'tar.c.DIFF'
  1324. *** /usr/src/bin/tar.c    Wed Nov 14 00:09:23 1984
  1325. --- tar.c    Wed Jul 24 12:26:38 1985
  1326. ***************
  1327. *** 27,32
  1328.    * Tape Archival Program
  1329.    */
  1330.   #include <stdio.h>
  1331.   #include <sys/param.h>
  1332.   #include <sys/stat.h>
  1333.   #include <sys/dir.h>
  1334.  
  1335. --- 27,33 -----
  1336.    * Tape Archival Program
  1337.    */
  1338.   #include <stdio.h>
  1339. + #include <rmt.h>    /* remote tape, must come before <sys/stat.h> */
  1340.   #include <sys/param.h>
  1341.   #include <sys/stat.h>
  1342.   #include <sys/dir.h>
  1343. ***************
  1344. *** 306,311
  1345.           doxtract(argv);
  1346.       else
  1347.           dotable();
  1348.       done(0);
  1349.   }
  1350.   
  1351.  
  1352. --- 307,313 -----
  1353.           doxtract(argv);
  1354.       else
  1355.           dotable();
  1356. +     close (mt);
  1357.       done(0);
  1358.   }
  1359.   
  1360. ***************
  1361. *** 722,728
  1362.           if (checkdir(dblock.dbuf.name))
  1363.               continue;
  1364.           if (dblock.dbuf.linkflag == '2') {
  1365. !             unlink(dblock.dbuf.name);
  1366.               if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
  1367.                   fprintf(stderr, "tar: %s: symbolic link failed\n",
  1368.                       dblock.dbuf.name);
  1369.  
  1370. --- 724,736 -----
  1371.           if (checkdir(dblock.dbuf.name))
  1372.               continue;
  1373.           if (dblock.dbuf.linkflag == '2') {
  1374. !             /*
  1375. !              * only unlink non-directories or empty directories
  1376. !              */
  1377. !             if (rmdir (dblock.dbuf.name) < 0) {
  1378. !                 if (errno == ENOTDIR)
  1379. !                     unlink(dblock.dbuf.name);
  1380. !             }
  1381.               if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
  1382.                   fprintf(stderr, "tar: %s: symbolic link failed\n",
  1383.                       dblock.dbuf.name);
  1384. ***************
  1385. *** 749,755
  1386.               continue;
  1387.           }
  1388.           if (dblock.dbuf.linkflag == '1') {
  1389. !             unlink(dblock.dbuf.name);
  1390.               if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
  1391.                   fprintf(stderr, "tar: %s: cannot link\n",
  1392.                       dblock.dbuf.name);
  1393.  
  1394. --- 757,769 -----
  1395.               continue;
  1396.           }
  1397.           if (dblock.dbuf.linkflag == '1') {
  1398. !             /*
  1399. !              * only unlink non-directories or empty directories
  1400. !              */
  1401. !             if (rmdir (dblock.dbuf.name) < 0) {
  1402. !                 if (errno == ENOTDIR)
  1403. !                     unlink(dblock.dbuf.name);
  1404. !             }
  1405.               if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
  1406.                   fprintf(stderr, "tar: %s: cannot link\n",
  1407.                       dblock.dbuf.name);
  1408. SHAR_EOF
  1409. #    End of shell archive
  1410. exit 0
  1411.  
  1412.